//
// Created by Administrator on 2022/10/29 0029.
//
#include <onix/rtc.h>
#include <onix/io.h>
#include <onix/interrupt.h>
#include <onix/debug.h>
#include <onix/time.h>

#define CMOS_ADDR   0x70
#define CMOS_DATA   0x71
#define CMOS_NMI    0x80

#define CMOS_A      0x0A
#define CMOS_B      0x0B
#define CMOS_C      0x0C
#define CMOS_D      0x0D

#define CMOS_SECOND 0x01
#define CMOS_MINUTE 0x03
#define CMOS_HOUR   0x05

u8 cmos_read(u8 addr)
{
    outb(CMOS_ADDR, CMOS_NMI | addr);
    return inb(CMOS_DATA);
}

void cmos_write(u8 addr, u8 value)
{
    outb(CMOS_ADDR, CMOS_NMI | addr);
    outb(CMOS_DATA, value);
}

static u32 volatile counter = 0;

void rtc_handler(int vector)
{
    send_eoi(vector);
    cmos_read(CMOS_C);
    set_alarm(1);
    DEBUGK("rtc handler %d ...\n", counter++);
}

void set_alarm(u32 value)
{
    tm time;
    time_read(&time);

    u8 sec = value % 60;
    value /= 60;
    u8 min = value % 60;
    value /= 60;
    u32 hour = value;

    time.tm_sec += sec;
    if (time.tm_sec >= 60){
        time.tm_sec %= 60;
        time.tm_min += 1;
    }

    time.tm_min += min;
    if (time.tm_min >= 60){
        time.tm_min %= 60;
        time.tm_hour += 1;
    }

    time.tm_hour += (int)hour;
    if (time.tm_hour >= 24) {
        time.tm_hour %= 24;
    }

    cmos_write(CMOS_HOUR, bin_to_bcd(time.tm_hour));
    cmos_write(CMOS_MINUTE, bin_to_bcd(time.tm_min));
    cmos_write(CMOS_SECOND, bin_to_bcd(time.tm_sec));
}

void rtc_init()
{
    u8 prev;

    // 周期中断
//    cmos_write(CMOS_B, 0b01000010);
    // 闹钟中断
    cmos_write(CMOS_B, 0b00100010);
    cmos_read(CMOS_C);

    set_alarm(2);
    // 设置中断频率
    outb(CMOS_A, (inb(CMOS_A) & 0xF) | 0b1110);

    set_interrupt_handler(IRQ_RTC, rtc_handler);
    set_interrupt_mask(IRQ_RTC, TRUE);
    set_interrupt_mask(IRQ_CASCADE, TRUE);
}